package com.iqiyi.pps.epg.api.aop;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.iqiyi.pps.epg.api.aop.annotation.SkipAuthCheck;
import com.iqiyi.pps.epg.api.aop.annotation.SkipInterfaceLog;
import com.iqiyi.pps.epg.api.entity.CrossData;
import com.iqiyi.pps.epg.api.utils.CrossDataLocalPool;
import com.iqiyi.pps.epg.api.utils.ServiceUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by karkarrotxu on 2016/9/2.
 */

@Aspect
@Order(4)
public class SimpleAspect {
    private static final LocalVariableTableParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();

    public static final int SKIP_LARGE_SIZE = 4000;

    private static Logger logger = LoggerFactory.getLogger(SimpleAspect.class);

    @Pointcut("execution(public String com.iqiyi.pps.epg.api.server.proxy.*.*(..))")
    public void cutIn() {

    }

    @Around(value = "cutIn()")
    public Object aroundServiceActions(ProceedingJoinPoint pjp) {
        Object returnValue = null;
        String className = pjp.getTarget().getClass().getSimpleName();
        String methodName = pjp.getSignature().getName();
        MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
        Method method = joinPointObject.getMethod();
        CrossData crossData = CrossDataLocalPool.get();
        Map<String, String> apiMap = null;

        //     boolean skipLog = method.isAnnotationPresent(SkipInterfaceLog.class);
        SkipInterfaceLog skipInterfaceLog = method.getAnnotation(SkipInterfaceLog.class);
        boolean skipAuth = method.isAnnotationPresent(SkipAuthCheck.class);
        //    boolean hasValidate = method.isAnnotationPresent(ValidateGroup.class);
        try {
            if (skipInterfaceLog == null || skipInterfaceLog.needParams()) {
                Map<String, Object> params = makeUpParams(getParameterNames(method), pjp.getArgs());
                crossData.setParams(params);
                String strParam = JSON.toJSONString(params, SerializerFeature.WriteMapNullValue);
                apiMap = ServiceUtil.formatApiLogMap(strParam, crossData.getUriIfo(), crossData.getHttpHeaders());
            }

            if (!skipAuth) {
                returnValue = ServiceUtil.checkAuthorizationResponse(crossData.getHttpHeaders(), crossData.getUriIfo());
            }
//            if (returnValue == null &&  hasValidate) {
//                String errorMsg = doValidate(method.getAnnotation(ValidateGroup.class).fields(), pjp.getArgs());
//                if (errorMsg != null) {
//                    returnValue = ServiceUtil.getResponseError(errorMsg);
//                }
//            }

        } catch (Exception e) {
            logger.error("[" + className + "][" + methodName + "][" + pjp.getArgs() + "]", e);
            returnValue = ServiceUtil.getResponseError();
            return returnValue;
        }
        if (returnValue == null) {
            try {
                returnValue = pjp.proceed();
            } catch (Throwable e) {
                logger.error("[" + className + "][" + methodName + "][" + pjp.getArgs() + "]", e);
                returnValue = ServiceUtil.getResponseError();
            }
        }
        if (skipInterfaceLog == null && apiMap != null) {
            apiMap.put("resTime", String.valueOf(System.currentTimeMillis()));
            logger.info("[{}][{}][retValue={}]", className, methodName, returnValue);
            if (returnValue != null && returnValue.toString().length() > SKIP_LARGE_SIZE) {
                apiMap.put("response", "too large skip " + SKIP_LARGE_SIZE);
            } else {
                apiMap.put("response", "" + returnValue);
            }
            ServiceUtil.insertInterfaceLog(apiMap);
        }
        return returnValue;
    }

    private Map<String, Object> makeUpParams(String[] parameterNames, Object[] args) {
        Map<String, Object> map = new HashMap<String, Object>();
        if (parameterNames != null && parameterNames.length > 0) {
            int length = parameterNames.length;
            for (int i = 0; i < length; i++) {
                map.put(parameterNames[i], args[i]);
            }
        }
        return map;
    }

    public static String[] getParameterNames(Method method) {
        return parameterNameDiscoverer.getParameterNames(method);
    }

//    private static String doValidate(ValidateFiled[] validateFiles, Object[] args) {
//        String ret = null;
//        for (ValidateFiled validateFiled : validateFiles) {
//            if (validateFiled.multiCheck()) {
//                ret = multiCheck(validateFiled, args);
//            } else {
//                ret = singleCheck(validateFiled, args[validateFiled.index()]);
//            }
//            if (ret != null) {
//                return ret;
//            }
//        }
//        return ret;
//    }
//
//    private static String multiCheck(ValidateFiled validateFiled, Object[] args) {
//        String ret = null;
//        for (int index = 0; index < validateFiled.indexArr().length; index++) {
//            ret = singleCheck(validateFiled, args[validateFiled.indexArr()[index]]);
//            if (ret != null) {
//                return ret;
//            }
//        }
//        return ret;
//    }
//
//    private static String singleCheck(ValidateFiled validateFiled, Object arg) {
//        if (arg == null && validateFiled.notNull() == false) {
//            return null;
//        }
//        if (StringUtils.isBlank(arg.toString()) && validateFiled.notBlank() == false) {
//            return null;
//        }
//        ValidateFiled.ValidateType[] checkType = validateFiled.validateType();
//        boolean flag = false;
//        int errorMsgIndex = -1;
//        for (int i = 0; i < checkType.length; i++) {
//            switch (checkType[i]) {
//                case REGSTR:
//                    flag = RegUtil.regCheck(validateFiled.regStr(), "" + arg);
//                    if (!flag) {
//                        errorMsgIndex = i;
//                        break;
//                    }
//                    break;
//                case NOT_BLANK:
//                    flag = arg != null && arg.toString().trim().length() > 0;
//                    if (!flag) {
//                        errorMsgIndex = i;
//                        break;
//                    }
//                    break;
//            }
//        }
//        if (errorMsgIndex != -1) {
//            return validateFiled.errorMsg()[errorMsgIndex];
//        }
//        return null;
//    }
}


